
#include "FreeRTOS.h"
#include "task.h"
#include "stm32f0xx.h"
#include "semphr.h"

#define  BSP_ADC_MOD
#include "bsp_adc.h"


tADC bsp_adc;



/**
* @brief ADC MSP Initialization
* This function configures the hardware resources used in this example
* @param hadc: ADC handle pointer
* @retval None
*/
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hadc->Instance==ADC1)
  {
  /* USER CODE BEGIN ADC1_MspInit 0 */
		__HAL_RCC_DMA1_CLK_ENABLE();
  /* USER CODE END ADC1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_ADC1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**ADC GPIO Configuration
    PA3     ------> ADC_IN3
    PA4     ------> ADC_IN4
    */
    GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* ADC1 DMA Init */
    /* ADC Init */
    bsp_adc.hdma.Instance = DMA1_Channel1;
    bsp_adc.hdma.Init.Direction = DMA_PERIPH_TO_MEMORY;
    bsp_adc.hdma.Init.PeriphInc = DMA_PINC_DISABLE;
    bsp_adc.hdma.Init.MemInc = DMA_MINC_ENABLE;
    bsp_adc.hdma.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    bsp_adc.hdma.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    bsp_adc.hdma.Init.Mode = DMA_CIRCULAR;
    bsp_adc.hdma.Init.Priority = DMA_PRIORITY_MEDIUM;
    if (HAL_DMA_Init(&bsp_adc.hdma) != HAL_OK)
    {
      
    }

    __HAL_LINKDMA(hadc,DMA_Handle,bsp_adc.hdma);

  /* USER CODE BEGIN ADC1_MspInit 1 */
		HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 1, 0);
		HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);  
  /* USER CODE END ADC1_MspInit 1 */
  }

}

/**
* @brief ADC MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param hadc: ADC handle pointer
* @retval None
*/
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc)
{
  if(hadc->Instance==ADC1)
  {
  /* USER CODE BEGIN ADC1_MspDeInit 0 */

  /* USER CODE END ADC1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_ADC1_CLK_DISABLE();

    /**ADC GPIO Configuration
    PA3     ------> ADC_IN3
    PA4     ------> ADC_IN4
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_3|GPIO_PIN_4);

    /* ADC1 DMA DeInit */
    HAL_DMA_DeInit(hadc->DMA_Handle);
  /* USER CODE BEGIN ADC1_MspDeInit 1 */

  /* USER CODE END ADC1_MspDeInit 1 */
  }

}

HAL_StatusTypeDef bsp_adc_init_adc(tADC *adc)
{
	HAL_StatusTypeDef res = HAL_OK;

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC_Init 1 */

  /* USER CODE END ADC_Init 1 */

  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  */
  adc->hadc.Instance = ADC1;
  adc->hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  adc->hadc.Init.Resolution = ADC_RESOLUTION_12B;
  adc->hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  adc->hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
  adc->hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  adc->hadc.Init.LowPowerAutoWait = DISABLE;
  adc->hadc.Init.LowPowerAutoPowerOff = DISABLE;
  adc->hadc.Init.ContinuousConvMode = ENABLE;
  adc->hadc.Init.DiscontinuousConvMode = DISABLE;
  adc->hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  adc->hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  adc->hadc.Init.DMAContinuousRequests = ENABLE;
  adc->hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  if ((res = HAL_ADC_Init(&adc->hadc)) != HAL_OK)
  {
    return res;
  }

  /** Configure for the selected ADC regular channel to be converted.
  */
  sConfig.Channel = ADC_CHANNEL_3;
  sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
  if ((res = HAL_ADC_ConfigChannel(&adc->hadc, &sConfig)) != HAL_OK)
  {
    return res;
  }

  /** Configure for the selected ADC regular channel to be converted.
  */
  sConfig.Channel = ADC_CHANNEL_4;
  if ((res = HAL_ADC_ConfigChannel(&adc->hadc, &sConfig)) != HAL_OK)
  {
    return res;
  }

//  /** Configure for the selected ADC regular channel to be converted.
//  */
//  sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
//  if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
//  {
//    Error_Handler();
//  }

//  /** Configure for the selected ADC regular channel to be converted.
//  */
//  sConfig.Channel = ADC_CHANNEL_VREFINT;
//  if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
//  {
//    Error_Handler();
//  }

//  /** Configure for the selected ADC regular channel to be converted.
//  */
//  sConfig.Channel = ADC_CHANNEL_VBAT;
//  if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
//  {
//    Error_Handler();
//  }
  /* USER CODE BEGIN ADC_Init 2 */
	if ((res = HAL_ADC_Start_DMA(&adc->hadc,
												(uint32_t *)adc->adc_data,
												BSP_ADC_CHANNEL_NUL
											 )) != HAL_OK)
	{
		return res;
	}				
		
	return res;
}


HAL_StatusTypeDef bsp_adc_semaphore_init(tADC *adc)
{
	adc->semaphore = xSemaphoreCreateBinary();

	if (adc->semaphore == NULL)
	{
		return HAL_ERROR;
	}
	
	return HAL_OK;
}


HAL_StatusTypeDef bsp_adc_init(tADC *adc)
{
	HAL_StatusTypeDef res = HAL_OK;
	
	res = bsp_adc_semaphore_init(adc);
	
	if (res != HAL_OK)
	{
		return res;
	}
	
	res = bsp_adc_init_adc(adc);
	
	return res;
}


void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
	BaseType_t pxHigherPriorityTaskWoken;
  uint32_t ulReturn;

  ulReturn = taskENTER_CRITICAL_FROM_ISR();
 
	if (hadc->DMA_Handle->Instance == DMA1_Channel1)
	{
		xSemaphoreGiveFromISR(bsp_adc.semaphore, &pxHigherPriorityTaskWoken);
		portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
	}
	
	taskEXIT_CRITICAL_FROM_ISR(ulReturn);
}











